using System;

namespace IQIGame.Onigao.Game
{
    public struct QuaternionLogic : IEquatable<QuaternionLogic>
    {
        public float x;
        public float y;
        public float z;
        public float w;

        private static readonly QuaternionLogic identityQuaternion = new QuaternionLogic(0f, 0f, 0f, 1f);

        public static QuaternionLogic identity => identityQuaternion;

        public QuaternionLogic(float x, float y, float z, float w)
        {
            this.x = x;
            this.y = y;
            this.z = z;
            this.w = w;
        }

        public static QuaternionLogic Euler(Vector3Logic euler)
        {
            return Euler(euler.x, euler.y, euler.z);
        }

        public static QuaternionLogic Euler(float x, float y, float z)
        {
            // 将角度转换为弧度
            float rollRad = x * MathLogic.Deg2Rad;
            float pitchRad = y * MathLogic.Deg2Rad;
            float yawRad = z * MathLogic.Deg2Rad;

            // 计算每个轴的四元数
            float cy = MathLogic.Cos(yawRad * 0.5f);
            float sy = MathLogic.Sin(yawRad * 0.5f);
            float cp = MathLogic.Cos(pitchRad * 0.5f);
            float sp = MathLogic.Sin(pitchRad * 0.5f);
            float cr = MathLogic.Cos(rollRad * 0.5f);
            float sr = MathLogic.Sin(rollRad * 0.5f);

            // 组合四元数
            QuaternionLogic q = new QuaternionLogic(
                sr * cp * cy - cr * sp * sy,
                cr * sp * cy + sr * cp * sy,
                cr * cp * sy - sr * sp * cy,
                cr * cp * cy + sr * sp * sy
            );

            return q;
        }

        public static QuaternionLogic operator *(QuaternionLogic lhs, QuaternionLogic rhs)
        {
            return new QuaternionLogic(lhs.w * rhs.x + lhs.x * rhs.w + lhs.y * rhs.z - lhs.z * rhs.y, lhs.w * rhs.y + lhs.y * rhs.w + lhs.z * rhs.x - lhs.x * rhs.z, lhs.w * rhs.z + lhs.z * rhs.w + lhs.x * rhs.y - lhs.y * rhs.x, lhs.w * rhs.w - lhs.x * rhs.x - lhs.y * rhs.y - lhs.z * rhs.z);
        }

        public static Vector3Logic operator *(QuaternionLogic rotation, Vector3Logic point)
        {
            float num = rotation.x * 2f;
            float num2 = rotation.y * 2f;
            float num3 = rotation.z * 2f;
            float num4 = rotation.x * num;
            float num5 = rotation.y * num2;
            float num6 = rotation.z * num3;
            float num7 = rotation.x * num2;
            float num8 = rotation.x * num3;
            float num9 = rotation.y * num3;
            float num10 = rotation.w * num;
            float num11 = rotation.w * num2;
            float num12 = rotation.w * num3;
            Vector3Logic result = default;
            result.x = (1f - (num5 + num6)) * point.x + (num7 - num12) * point.y + (num8 + num11) * point.z;
            result.y = (num7 + num12) * point.x + (1f - (num4 + num6)) * point.y + (num9 - num10) * point.z;
            result.z = (num8 - num11) * point.x + (num9 + num10) * point.y + (1f - (num4 + num5)) * point.z;
            return result;
        }

        private static bool IsEqualUsingDot(float dot)
        {
            return dot > 0.999999f;
        }

        public static bool operator ==(QuaternionLogic lhs, QuaternionLogic rhs)
        {
            return IsEqualUsingDot(Dot(lhs, rhs));
        }

        public static bool operator !=(QuaternionLogic lhs, QuaternionLogic rhs)
        {
            return !(lhs == rhs);
        }

        public static float Dot(QuaternionLogic a, QuaternionLogic b)
        {
            return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w;
        }

        public static QuaternionLogic Normalize(QuaternionLogic q)
        {
            float num = MathLogic.Sqrt(Dot(q, q));
            if (num < float.Epsilon)
            {
                return identity;
            }

            return new QuaternionLogic(q.x / num, q.y / num, q.z / num, q.w / num);
        }

        public void Normalize()
        {
            this = Normalize(this);
        }

        public override int GetHashCode()
        {
            return x.GetHashCode() ^ (y.GetHashCode() << 2) ^ (z.GetHashCode() >> 2) ^ (w.GetHashCode() >> 1);
        }

        public override bool Equals(object other)
        {
            if (!(other is QuaternionLogic))
            {
                return false;
            }

            return Equals((QuaternionLogic)other);
        }

        public bool Equals(QuaternionLogic other)
        {
            return x.Equals(other.x) && y.Equals(other.y) && z.Equals(other.z) && w.Equals(other.w);
        }
    }
}
